const express = require('express');
const router = express.Router();
const Challenge = require('../models/Challenge');
const Pattern = require('../models/Pattern');
const Progress = require('../models/Progress');
const User = require('../models/User');
const auth = require('../middleware/auth');
const AIService = require('../services/ai/aiService');

// Initialize AI service
const aiService = new AIService();

/**
 * @route   GET api/challenges
 * @desc    Get all challenges
 * @access  Private
 */
router.get('/', auth, async (req, res) => {
  try {
    const challenges = await Challenge.find()
      .populate('pattern', 'name category')
      .sort({ level: 1, pattern: 1 });
    
    res.json(challenges);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server Error');
  }
});

/**
 * @route   GET api/challenges/:id
 * @desc    Get challenge by ID
 * @access  Private
 */
router.get('/:id', auth, async (req, res) => {
  try {
    const challenge = await Challenge.findById(req.params.id)
      .populate('pattern', 'name category description');
    
    if (!challenge) {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    res.json(challenge);
  } catch (err) {
    console.error(err.message);
    
    if (err.kind === 'ObjectId') {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    res.status(500).send('Server Error');
  }
});

/**
 * @route   GET api/challenges/pattern/:patternId
 * @desc    Get challenges by pattern ID
 * @access  Private
 */
router.get('/pattern/:patternId', auth, async (req, res) => {
  try {
    // Get user's current level
    const user = await User.findById(req.user.id);
    const currentLevel = user.progress.currentLevel;
    
    // Get challenges for the pattern at the user's current level
    let challenges = await Challenge.find({
      pattern: req.params.patternId,
      level: currentLevel
    }).populate('pattern', 'name category');
    
    // If no challenges found, generate one
    if (challenges.length === 0) {
      try {
        // Get pattern details
        const pattern = await Pattern.findById(req.params.patternId);
        
        if (!pattern) {
          return res.status(404).json({ msg: 'Pattern not found' });
        }
        
        // Generate challenge using AI
        const challengeData = await aiService.generateChallenge(
          pattern.name,
          pattern.category,
          currentLevel
        );
        
        // Create new challenge
        const newChallenge = new Challenge({
          title: challengeData.title,
          description: challengeData.description,
          pattern: req.params.patternId,
          level: currentLevel,
          scenario: challengeData.scenario,
          requirements: challengeData.requirements,
          hints: challengeData.hints,
          sampleSolution: challengeData.sampleSolution,
          timeLimit: challengeData.timeLimit,
          difficulty: challengeData.difficulty,
          tags: [pattern.name.toLowerCase().replace(' ', '-'), currentLevel, pattern.category.toLowerCase()]
        });
        
        await newChallenge.save();
        
        // Add the new challenge to the result
        newChallenge.pattern = {
          _id: pattern._id,
          name: pattern.name,
          category: pattern.category
        };
        
        challenges = [newChallenge];
      } catch (error) {
        console.error('Challenge generation error:', error);
        // Return empty array if generation fails
        challenges = [];
      }
    }
    
    res.json(challenges);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server Error');
  }
});

/**
 * @route   GET api/challenges/level/:level
 * @desc    Get challenges by level
 * @access  Private
 */
router.get('/level/:level', auth, async (req, res) => {
  try {
    const challenges = await Challenge.find({ level: req.params.level })
      .populate('pattern', 'name category')
      .sort({ pattern: 1 });
    
    res.json(challenges);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server Error');
  }
});

/**
 * @route   POST api/challenges
 * @desc    Create a challenge
 * @access  Private/Admin
 */
router.post('/', auth, async (req, res) => {
  // Check if user is admin
  if (req.user.role !== 'admin') {
    return res.status(403).json({ msg: 'Not authorized' });
  }
  
  const {
    title,
    description,
    pattern,
    level,
    scenario,
    requirements,
    hints,
    sampleSolution,
    testCases,
    timeLimit,
    difficulty,
    tags
  } = req.body;
  
  try {
    // Check if pattern exists
    const patternExists = await Pattern.findById(pattern);
    
    if (!patternExists) {
      return res.status(404).json({ msg: 'Pattern not found' });
    }
    
    // Create new challenge
    const challenge = new Challenge({
      title,
      description,
      pattern,
      level,
      scenario,
      requirements,
      hints,
      sampleSolution,
      testCases,
      timeLimit,
      difficulty,
      tags
    });
    
    await challenge.save();
    res.json(challenge);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server Error');
  }
});

/**
 * @route   PUT api/challenges/:id
 * @desc    Update a challenge
 * @access  Private/Admin
 */
router.put('/:id', auth, async (req, res) => {
  // Check if user is admin
  if (req.user.role !== 'admin') {
    return res.status(403).json({ msg: 'Not authorized' });
  }
  
  try {
    const challenge = await Challenge.findById(req.params.id);
    
    if (!challenge) {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    // Update fields
    const updateFields = { ...req.body };
    Object.keys(updateFields).forEach(key => {
      challenge[key] = updateFields[key];
    });
    
    await challenge.save();
    res.json(challenge);
  } catch (err) {
    console.error(err.message);
    
    if (err.kind === 'ObjectId') {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    res.status(500).send('Server Error');
  }
});

/**
 * @route   DELETE api/challenges/:id
 * @desc    Delete a challenge
 * @access  Private/Admin
 */
router.delete('/:id', auth, async (req, res) => {
  // Check if user is admin
  if (req.user.role !== 'admin') {
    return res.status(403).json({ msg: 'Not authorized' });
  }
  
  try {
    const challenge = await Challenge.findById(req.params.id);
    
    if (!challenge) {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    await challenge.remove();
    res.json({ msg: 'Challenge removed' });
  } catch (err) {
    console.error(err.message);
    
    if (err.kind === 'ObjectId') {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    res.status(500).send('Server Error');
  }
});

/**
 * @route   POST api/challenges/:id/submit
 * @desc    Submit a solution for evaluation
 * @access  Private
 */
router.post('/:id/submit', auth, async (req, res) => {
  try {
    const { solution } = req.body;
    
    if (!solution) {
      return res.status(400).json({ msg: 'Solution is required' });
    }
    
    // Get the challenge
    const challenge = await Challenge.findById(req.params.id)
      .populate('pattern', 'name');
    
    if (!challenge) {
      return res.status(404).json({ msg: 'Challenge not found' });
    }
    
    // Get or create progress record
    let progress = await Progress.findOne({
      user: req.user.id,
      challenge: challenge._id,
      pattern: challenge.pattern._id,
      level: challenge.level
    });
    
    if (!progress) {
      progress = new Progress({
        user: req.user.id,
        challenge: challenge._id,
        pattern: challenge.pattern._id,
        level: challenge.level
      });
    }
    
    // Update progress
    progress.status = 'submitted';
    progress.attempts += 1;
    progress.lastSubmission = {
      code: solution,
      submittedAt: Date.now()
    };
    
    await progress.save();
    
    // Evaluate the solution using AI
    try {
      // Get user's preferred AI provider
      const user = await User.findById(req.user.id);
      const aiProvider = user.preferences.aiProvider;
      
      const evaluation = await aiService.evaluateSolution(
        challenge.pattern.name,
        challenge.description,
        solution,
        challenge.level,
        aiProvider
      );
      
      // Update progress with evaluation
      progress.evaluation = {
        rating: evaluation.rating,
        feedback: evaluation.feedback,
        suggestions: evaluation.suggestions,
        correctPatternUsage: evaluation.correctPatternUsage,
        evaluatedAt: Date.now()
      };
      
      // Check if solution meets minimum requirements
      if (
        evaluation.rating === 'Satisfactory' || 
        evaluation.rating === 'Good' || 
        evaluation.rating === 'Excellent'
      ) {
        progress.completed = true;
        progress.completedAt = Date.now();
        progress.status = 'completed';
        
        // Update user progress
        await User.findByIdAndUpdate(req.user.id, {
          $addToSet: {
            [`progress.completedPatterns.${challenge.level}`]: challenge.pattern._id
          }
        });
      }
      
      await progress.save();
      
      res.json({
        evaluation,
        progress: {
          completed: progress.completed,
          attempts: progress.attempts,
          rating: evaluation.rating
        }
      });
    } catch (error) {
      console.error('AI evaluation error:', error);
      res.status(500).json({ 
        msg: 'Error evaluating solution', 
        error: error.message 
      });
    }
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server Error');
  }
});

module.exports = router; 